iT邦幫忙

2023 iThome 鐵人賽

DAY 25
0
Software Development

Laravel專案練習-寶可夢管理系統系列 第 25

Day25:寶可夢專案-學習寫測試-UnitTest實作

  • 分享至 

  • xImage
  •  

關於單元測試的部分,我找到我的API部分有一個小功能蠻適合拿來做練習:

測試對象

function validSkillsForRace($skills, $race) {
    $allowedSkills = $race->skills->pluck('id')->toArray();
    
    foreach ($skills as $skillId) {
        if (!in_array($skillId, $allowedSkills)) {
            return false;
        }
    }
    return true;
}

這是我在使用者輸入參數新增寶可夢時,我進行表單驗證的時候,會用到的一個自定義邏輯,簡單講解一下:

  • 目的

    我會用這個驗證是因為我的技能欄位是用陣列來儲存,使用者可以輸入1~4個技能,所以我要一個一個去比對這些技能是否為該寶可夢可以學習的技能。

  • 功能細節

    • 首先參數的部分這裡我讓使用者傳入當前寶可夢的技能及種族(比如說皮卡丘)
    • 然後在輸入的種族object去取得他相關聯的技能id
    • 之後再去比對我輸入的技能是否存在種族可以學的技能陣列裡
    • 如果不存在回false,存在回true

unitTest實作

在前面的部分有提到模擬(mocking)的部分的用意,而我們這裡需要模擬的對象就是會實際對資料庫做查找的部分,以我上述的例子就是這段:

$race->skills->pluck('id')
  • 先詳細說說這整段laravel大概做了哪些事,
    1. $race->skills:
      • 這將返回一個 BelongsToMany 關聯的實例,代表 raceskills 之間的多對多關係。
    2. 在 Laravel 的底層,當您嘗試從 BelongsToMany 關聯中取得資料時(例如像 $race->skills->pluck('id') 這樣的操作),它會隱式地調用 getResults() 方法以從資料庫取得相對應的 skills
    3. getResults():
      • 這會返回一個 Collection 實例,其中包含與該 race 相關的所有 skills
    4. $race->skills->pluck('id'):
      • 這會在上述的 Collection 實例上調用 pluck 方法,從集合中取得每個 skillid 值,並返回這些值的集合。

這裡我必須將這段會返回的物件都做創建模擬物件(以上述來說的話就是$race、BelongsToMany、Collection這些實例):

public function testValidSkillsForRaceIftheSkillsExist()
    {
        // 创建 Race 类的模拟对象
        $raceMock = $this->getMockBuilder(Race::class)
            ->onlyMethods(['skills']) // 指定仅模拟 `skills` 方法
            ->getMock();
    
        // 创建 Collection 类的模拟对象
        // 模拟了 BelongsToMany 关系类的一个实例,用来模拟 $race->skills 的返回值。
        $skillsRelationMock = $this->createMock(BelongsToMany::class);
        // 模拟了 Collection 类的一个实例,用来模拟 $race->skills->pluck('id') 的返回值。
        $skillsCollectionMock = $this->createMock(Collection::class);
    
            

這裡簡單來說就是我創建了:

Race、BelongsToMany、collecetion類的模擬物件。

// 修改这里:使 `pluck` 返回 Collection 对象而不是数组
        $skillsCollectionMock->method('pluck')
            ->willReturn(collect([1, 2, 3]));
    
        // Laravel 在底层会调用 getResults 来获取这个关系对应的模型集合。
        $skillsRelationMock->method('getResults')
            ->willReturn($skillsCollectionMock);
    
        $raceMock->method('skills')
            ->willReturn($skillsRelationMock);
    
        // 上述過程都在模擬$race->skills->pluck('id')  

        
    

這裡我讓整個我是將$race->skills->pluck('id')整個過程都用模擬物件先定義好,

也就是當我在call這些物件的某些方法的時候他會如何去執行,
比如 $raceMock->method('skills')
->willReturn($skillsRelationMock);
這裡就是當我$race去→skills的時候,原本返回的事BelongsToMany物件,這裡返回的是我創建的模擬物件。

 // 调用待测函数,并检查返回值
        $result = validSkillsForRace([1, 2], $raceMock);
    
        // 断言结果为真
        $this->assertTrue($result);

}

最後我就可以實際去呼叫我要測試的函式,除了傳入原本需要傳入的技能id陣列,還有剛剛模擬的物件,這樣在我實際函數裡面$race物件去資料庫撈資料的時候,他會去用模擬的方式得到[1,2,3]陣列。

小結語

這裡我其實並沒有把我整個專案裡面的測試都寫完,我主要還是以練習為導向,所以挑了一些測試對象來練習FeatureTest及UnitTest,實際上一定更複雜要注意的事情更多,這裡就是單純跟大家分享我初次練習測試的小心得,希望未來需要寫的時候能有一個初步了解。


上一篇
Day24:寶可夢專案-學習寫測試-featureTest實作
下一篇
Day26:寶可夢專案-Docker練習-基本概念
系列文
Laravel專案練習-寶可夢管理系統30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言